home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / utilprn / hpdeskje.sit / HPDJet ƒ / PDEF0.c < prev    next >
C/C++ Source or Header  |  1989-04-02  |  14KB  |  467 lines

  1. /* 02.04.1989  amn  (latest edit) */
  2.  
  3. /* PDEF0.c  -  printer driver for Macintosh and HP DeskJet, draft printing. */
  4.  
  5. /* Compiles into 'PDEF' resource, id 0, name ''. */
  6. /* We cannot use any global variables in this code.  However, the globals of the */
  7. /* low-level driver (XPrint) are available thru the handle 'dCtlStorage' in the */
  8. /* driver's device control entry. */
  9.  
  10. /* This resource is placed into the printer resource file */
  11. /* 'HP DeskJet', type 'PRER', creator 's89^' as */
  12. /* 'PDEF' 0 '' by 'PRER_Builder' utility program.  This utility adds a small jump */
  13. /* table in front of the code produced by LightspeedC. */
  14.  
  15. /* These procedures handle draft printing, ie. direct commands to printer. */
  16. /* HP DeskJet is quite capable of accepting direct print head positioning: */
  17. /* it tries to accumulate print data in its 16 kB buffer and sort it out */
  18. /* to print it in optimal order.  Thus we don't try to avoid reverse line feeds. */
  19.  
  20. /* Authors:  Ari Mujunen (amn@hutcs.hut.fi) and Olli Arnberg (oar@hutcs.hut.fi). */
  21. /* Copyright Ari Mujunen, Olli Arnberg 1989. */
  22. /* You may redistribute the driver (=printer resource file, source files, */
  23. /* documentation file(s), and the file 'Copyright and Source Offer') */
  24. /* only _non-commercially_ and _in its entirety_. */
  25. /* See the file 'Copyright and Source Offer' and/or documentation for details. */
  26. /* Acknowledgements:  Special thanks to Mr. Earle R. Horton for his 'Daisy' */
  27. /* daisywheel printer driver and its source code published in 'MacTutor', Nov-Dec 1987. */
  28. /* This driver served as a basis and inspiration for our work.  It also */
  29. /* proofed that a Macintosh printer driver can be done despite the lack of */
  30. /* documentation from Apple. */
  31.  
  32. /* Change history: */
  33. /* Version  When        Who      Why */
  34. /* 2.0      21.11.1988  amn      Original rewrite. */
  35. /*          23.11.1988  amn      Simplistic draft (direct positioning commands to printer). */
  36. /*          24.11.1988  amn      Read printed listing... */
  37. /*          25.11.1988  amn      Implementing justified text, ie. SpaceExtra. */
  38. /*          27.11.1988  amn      Implementing justified text, ie. SpaceExtra. */
  39. /*          09.12.1988  amn      User-specifiable setting 'movePrintPositionBeforeEachWord'. */
  40. /*          12.12.1988  amn      HP DeskJet physical margins taken into account. */
  41. /*          07.03.1989  amn      Character conversion table from Mac to HP Roman8. */
  42. /*          10.03.1989  amn      Call stdText with Ptr, not QDPtr to text buffer. */
  43. /*          25.03.1989  amn,oar  The global file refNums are not used any longer because of MF. */
  44. /*          28.03.1989  amn      Settable printer origin. */
  45. /* 2.1      02.04.1989  amn,oar  Released version. */
  46.  
  47.  
  48. #include "common_mac_includes.h"
  49.  
  50. /* Mac OS includes specific to this module: */
  51. #include <pascal.h>
  52.  
  53.  
  54. #include "prglobals.h"
  55.  
  56. #include "procedures_for_PDEF1.c"
  57. #include "procedures_for_PDEF5.c"
  58.  
  59.  
  60.  
  61. /* Function prototypes. */
  62.  
  63. /* Procedure dispatcher. */
  64. void main(int);
  65.  
  66. /* Initializes a specialized grafPort for printing. */
  67. pascal TPPrPort myPrOpenDoc(THPrint, TPPrPort, Ptr);
  68.  
  69. /* Disposes the printing grafPort. */
  70. pascal void myPrCloseDoc(TPPrPort);
  71.  
  72. /* Reinitializes the printing grafPort. */
  73. pascal void myPrOpenPage(TPPrPort, TPRect);
  74.  
  75. /* Feeds next sheet. :-) */
  76. pascal void myPrClosePage(TPPrPort);
  77.  
  78.  
  79. /* Replaces the standard QuickDraw low-level procedure for drawing text. */
  80. pascal void myStdText(int, Ptr, Point, Point);
  81. void printOneWord(int, Ptr, Point, Point);
  82.  
  83. /* Used to call standard QD text-drawing procedure.  We use prototypes... */
  84. pascal void CallPascal(int, Ptr, Point, Point, Ptr);
  85.  
  86.  
  87.  
  88. /* Function definitions. */
  89.  
  90.  
  91. void
  92. main(routineSelector)
  93. int routineSelector;
  94. {
  95.     /* The jump table code inserted before our code resource by 'PRER_Builder' */
  96.     /* utility program pushes a word onto stack indicating which routine is called. */
  97.     /* We pop it off the stack and select an appropriate routine. */
  98.     
  99.     switch(routineSelector) {
  100.         case 0:
  101.             asm {
  102.                 unlk a6  ;; LSC generates an 'link' instruction to access parameters
  103.                 move.l (a7)+, d0  ;; pop return address to our jump table code (discarded)
  104.                 move.w (a7)+, d0  ;; pop argument 'routineSelector'
  105.                 jmp myPrOpenDoc
  106.             }
  107.         case 1:
  108.             asm {
  109.                 unlk a6
  110.                 move.l (a7)+, d0
  111.                 move.w (a7)+, d0
  112.                 jmp myPrCloseDoc
  113.             }
  114.         case 2:
  115.             asm {
  116.                 unlk a6
  117.                 move.l (a7)+, d0
  118.                 move.w (a7)+, d0
  119.                 jmp    myPrOpenPage
  120.             }
  121.         case 3:
  122.             asm {
  123.                 unlk a6
  124.                 move.l (a7)+, d0
  125.                 move.w (a7)+, d0
  126.                 jmp    myPrClosePage
  127.             }
  128.     }  /* switch */
  129.     
  130.     /* We should not arrive here; Printing Manager has called a non-existent routine. */
  131.     SysError(5);  /* check bounds trap ??? */
  132. }  /* main */
  133.  
  134.  
  135. /* 
  136. This function is supposed to return a pointer to a specialized GrafPort (a TPrPort) customized
  137. for printing. Due to the paucity of documentation on how to go about this, I do not know whether
  138. I am going about this in exactly the right way, but I sure hope so. I set portBits.bounds for 
  139. the port to the empty Rect (0,0,0,0) and then install the standard QuickDraw routines as 
  140. GrafProcs. In place of StdText, I put my own StdText routine.  Hopefully, QuickDraw will keep
  141. track of the correct pen location for me, and call my routine whenever it is necessary to draw
  142. text.
  143. Other tasks: save a copy of the user print record in the printer resource file
  144. to remember user's last choices in job dialog (resolution etc.).
  145. */
  146.  
  147.  
  148. #define DEBUG_OPEN_PRINT_RECORD
  149.  
  150. pascal TPPrPort
  151. myPrOpenDoc(hPrint, pPrPort, pIOBuf)
  152. THPrint  hPrint;
  153. TPPrPort pPrPort;
  154. Ptr pIOBuf;
  155. {
  156.     TPPrPort thisPort;
  157.     ptXprintGlobals xPrintGlobals;
  158.     ptPrParam pXPrintParameterBlock;
  159.     OSErr retCode;
  160.     
  161.     {  /* Lock this code resource in memory (Printing Manager should do this, but...). */
  162.         Handle    us;
  163.         
  164.         us = (Handle)GetResource('PDEF', 0);
  165.         if (us == nil) {
  166.             PrintErr = ResError();
  167.             return(nil);
  168.         }
  169.         HLock(us);
  170.     }
  171.  
  172.     if (pPrPort == nil) {  /* printing GrafPort NOT preallocated */
  173.         if ((thisPort = (TPPrPort)NewPtr((long)sizeof(TPrPort))) == nil) {
  174.             PrintErr = iMemFullErr;
  175.             return(nil);
  176.         }
  177.         thisPort->fOurPtr = TRUE;
  178.     }
  179.     else {  /* printing GrafPort already preallocated */
  180.         thisPort = pPrPort;
  181.         thisPort->fOurPtr = FALSE;
  182.     }
  183.     
  184.     xPrintGlobals = GET_XPRINT_GLOBALS;
  185.     pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
  186.  
  187.     
  188.     /* Initialize GrafPort */
  189.     OpenPort(&thisPort->gPort);
  190.     setRectsAndRgns(thisPort, hPrint);
  191.     
  192.     /* Fill out QuickDraw low-level drawing procedures (gProcs) for this port. */
  193.     SetStdProcs(&thisPort->gProcs);
  194.     thisPort->gProcs.textProc = (QDPtr)myStdText;
  195.     thisPort->gPort.grafProcs = &thisPort->gProcs;
  196.     
  197.     /* Initialize the printer using standard printer control call. */
  198.     pXPrintParameterBlock->csCode = iPrDevCtl;
  199.     pXPrintParameterBlock->lParam1 = lPrReset;
  200.     if ((retCode = PBControl(pXPrintParameterBlock, FALSE)) != noErr)
  201.         goto cleanUp;
  202.  
  203. #define NUMBER_OF_THIS_PDEF 0
  204. #include "save_last_used.c"
  205.     
  206.     /* Page range etc. are available in global print record. */
  207.     xPrintGlobals->printRecord = **hPrint;
  208.     
  209.     /* If application has not requested an own idle procedure, we set our default one. */
  210.     if (xPrintGlobals->printRecord.prJob.pIdleProc == nil)
  211.         xPrintGlobals->printRecord.prJob.pIdleProc = (ProcPtr)checkForCommandPeriod;
  212.         
  213.     /* High-level printing code always counts pages from 1 (IM II-156). */
  214.     xPrintGlobals->pageCounter = 1;
  215.  
  216.     retCode = noErr;
  217. cleanUp:
  218.     PrintErr = retCode;
  219.     if (retCode == noErr)
  220.         return(thisPort);
  221.     else {
  222.         if (thisPort->fOurPtr)
  223.             DisposPtr(thisPort);
  224.         return(nil);
  225.     }
  226. }  /* myOpenDoc */
  227.  
  228.  
  229. pascal void
  230. myPrCloseDoc(pPrPort)
  231. TPPrPort  pPrPort;
  232. {
  233.     if (pPrPort == nil)
  234.         return;
  235.     
  236.     ClosePort(pPrPort);
  237.     if (pPrPort->fOurPtr)
  238.         DisposPtr(pPrPort);
  239. }  /* myPrCloseDoc */
  240.  
  241.  
  242. pascal void
  243. myPrOpenPage(pPrPort, pPageFrame)
  244. TPPrPort pPrPort;
  245. TPRect pPageFrame;
  246. {
  247.     ptXprintGlobals xPrintGlobals;
  248.     TPPrint pPrint;
  249.  
  250.     if (pPrPort == nil)
  251.         return;
  252.     
  253.     /* Don't touch 'pPageFrame' in draft mode (IM II-159). */
  254.  
  255.     xPrintGlobals = GET_XPRINT_GLOBALS;
  256.     
  257.     /* Port should be returned to initial state (as initialized in OpenDoc). ??? */
  258.     InitPort(pPrPort);
  259.     pPrint = &xPrintGlobals->printRecord;
  260.     setRectsAndRgns(pPrPort, &pPrint);
  261.     
  262.     /* Fill out QuickDraw low-level drawing procedures (gProcs) for this port. */
  263.     SetStdProcs(&pPrPort->gProcs);
  264.     pPrPort->gProcs.textProc = (QDPtr)myStdText;
  265.     pPrPort->gPort.grafProcs = &pPrPort->gProcs;
  266.  
  267.     /* if (PrintErr != noErr)  then some kind of error has occurred during previous page. */
  268.     /* Applications shouldn't call us then, but... */
  269.     
  270.     if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
  271.         && (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)
  272.         && (PrintErr == noErr)
  273.         && (xPrintGlobals->printRecord.prStl.feed == feedCut))
  274.         if (waitNextPage() == FALSE)  /* Dialog 'Insert next sheet...' */
  275.             PrintErr = iPrAbort;
  276. }  /* myPrOpenPage */
  277.  
  278.  
  279. pascal void
  280. myPrClosePage(pPrPort)
  281. TPPrPort pPrPort;
  282. {
  283.     ptXprintGlobals xPrintGlobals;
  284.     ptPrParam pXPrintParameterBlock;
  285.     OSErr retCode;
  286.     
  287.     if (pPrPort == nil)
  288.         return;
  289.         
  290.     /* if (PrintErr != noErr)  then some kind of error has occurred during page. */
  291.     /* Applications will call us nevertheless. */
  292.     
  293.     xPrintGlobals = GET_XPRINT_GLOBALS;
  294.     pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
  295.  
  296.     if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
  297.         && (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)) {
  298.         /* Form feed using standard printer control call. */
  299.         pXPrintParameterBlock->csCode = iPrDevCtl;
  300.         pXPrintParameterBlock->lParam1 = lPrPageEnd;
  301.         if ((retCode = PBControl(pXPrintParameterBlock, FALSE)) != noErr)
  302.             PrintErr = retCode;
  303.     }
  304.     
  305.     xPrintGlobals->pageCounter++;
  306. }  /* myClosePage */
  307.  
  308.  
  309. /*** #define DEBUG_TEXT_DRAWING ***/
  310.  
  311. pascal void
  312. myStdText(byteCount, textBuffer, numer, denom)
  313. int        byteCount;
  314. Ptr    textBuffer;
  315. Point    numer, denom;
  316. {
  317.     ptXprintGlobals xPrintGlobals;
  318.     GrafPtr savePort;
  319.     
  320.     xPrintGlobals = GET_XPRINT_GLOBALS;
  321.     
  322.     GetPort(&savePort);
  323.     (*(xPrintGlobals->printRecord.prJob.pIdleProc))();
  324.     SetPort(savePort);
  325.     
  326.     if ((xPrintGlobals->pageCounter >= xPrintGlobals->printRecord.prJob.iFstPage)
  327.         && (xPrintGlobals->pageCounter <= xPrintGlobals->printRecord.prJob.iLstPage)
  328.         && (PrintErr == noErr))
  329.     {
  330.         int i, startOfWord;
  331.         GrafPtr gp;
  332.  
  333. #define CHARACTERS 0
  334. #define BLANKS 1
  335.  
  336.         startOfWord = 0;
  337.         GetPort(&gp);
  338.         if ((!(xPrintGlobals->currentSettings.movePrintPositionBeforeEachWord))
  339.             && (gp->spExtra == 0L))
  340.             /* we assume that accurate positioning of word beginnings is not required */
  341.             i = byteCount + 1;
  342.         else {
  343.             int state;
  344.             
  345.             i = 0;
  346.             state = CHARACTERS;
  347.             while(i<=byteCount) {
  348.                 switch(state) {
  349.                     case CHARACTERS:
  350.                         if (textBuffer[i] == ' ')
  351.                             state = BLANKS;
  352.                         else
  353.                             i++;
  354.                         break;
  355.                     case BLANKS:
  356.                         if (textBuffer[i] == ' ')
  357.                             i++;
  358.                         else {
  359.                             printOneWord(i-startOfWord, &textBuffer[startOfWord], numer, denom);
  360.                             startOfWord = i;            
  361.                             state = CHARACTERS;
  362.                         }
  363.                         break;
  364.                 }  /* switch */
  365.             }  /* while */
  366.         }
  367.         
  368.         /* Last (or only) word of this string. */
  369.         printOneWord(i-startOfWord-1, &textBuffer[startOfWord], numer, denom);
  370.         
  371.     }  /* if printing allowed */
  372. }  /* myStdText */
  373.  
  374.  
  375. void
  376. printOneWord(byteCount, textBuffer, numer, denom)
  377. int        byteCount;
  378. Ptr    textBuffer;
  379. Point    numer, denom;
  380. {
  381.     ptXprintGlobals xPrintGlobals;
  382.     ptPrParam pXPrintParameterBlock;
  383.     
  384.     Point thePoint;
  385.     long theLong;
  386.     Str255 theNumAsString;
  387.     QDProcs stdProcs;
  388.     StringHandle ct;  /* character conversion table */
  389.     int i;
  390.     Str255 convertedDeskJetWord;
  391.     
  392.     xPrintGlobals = GET_XPRINT_GLOBALS;
  393.     pXPrintParameterBlock = &xPrintGlobals->xPrintParameterBlock;
  394.     
  395.     GetPen(&thePoint);
  396.     LocalToGlobal(&thePoint);  /* Someone may have adjusted the origin. */
  397. #ifdef DEBUG_TEXT_DRAWING
  398.     printString((StringPtr)"\pAt (");
  399.     NumToString((long)thePoint.v, theNumAsString);
  400.     printString(theNumAsString);
  401.     printString((StringPtr)"\p,");
  402.     NumToString((long)thePoint.h, theNumAsString);
  403.     printString(theNumAsString);
  404.     printString((StringPtr)"\p) scaled ((");
  405.     NumToString((long)numer.v, theNumAsString);
  406.     printString(theNumAsString);
  407.     printString((StringPtr)"\p/");
  408.     NumToString((long)denom.v, theNumAsString);
  409.     printString(theNumAsString);
  410.     printString((StringPtr)"\p),(");
  411.     NumToString((long)numer.h, theNumAsString);
  412.     printString(theNumAsString);
  413.     printString((StringPtr)"\p/");
  414.     NumToString((long)denom.h, theNumAsString);
  415.     printString(theNumAsString);
  416.     printString((StringPtr)"\p)) ");
  417.     NumToString((long)byteCount, theNumAsString);
  418.     printString(theNumAsString);
  419.     printString((StringPtr)"\p characters:\r\n->");
  420. #else
  421.     /* Position print head.*/
  422.     printString((StringPtr)"\p\033&a");
  423.     theLong = (long)thePoint.v * 720L / (long)xPrintGlobals->printRecord.prInfo.iVRes;
  424.     NumToString(theLong, theNumAsString);
  425.     printString(theNumAsString);
  426.     printString((StringPtr)"\pV");
  427.     printString((StringPtr)"\p\033&a");
  428.     theLong = (long)thePoint.h * 720L / (long)xPrintGlobals->printRecord.prInfo.iHRes;
  429.     NumToString(theLong, theNumAsString);
  430.     printString(theNumAsString);
  431.     printString((StringPtr)"\pH");        
  432. #endif DEBUG_TEXT_DRAWING
  433.     
  434.     /* Convert characters from Mac code set to HP Roman8 using C89T-resource. */
  435.     if ((ct = (StringHandle)GetResource('C89T', 0)) != nil) {
  436.         LoadResource(ct);
  437.         for(
  438.             i=0;
  439.             i < ((byteCount>sizeof(convertedDeskJetWord))
  440.                 ?(sizeof(convertedDeskJetWord))
  441.                 :byteCount);
  442.             i++
  443.         )
  444.             convertedDeskJetWord[i] = (*ct)[((unsigned char *)textBuffer)[i]];
  445.         
  446.         pXPrintParameterBlock->lParam1 = (long)(&convertedDeskJetWord);
  447.         pXPrintParameterBlock->lParam2 = (long)(i);
  448.     }
  449.     else {
  450.         pXPrintParameterBlock->lParam1 = (long)textBuffer;
  451.         pXPrintParameterBlock->lParam2 = (long)byteCount;
  452.     }
  453.     
  454.     /* Send actual text. */
  455.     pXPrintParameterBlock->csCode = iPrIOCtl;
  456.     /* retCode = */ PBControl(pXPrintParameterBlock, FALSE);
  457.         /* This must remain synchronous I/O, otherwise the local buffer may disappear. */
  458.  
  459. #ifdef DEBUG_TEXT_DRAWING
  460.     printString((StringPtr)"\p<-\r\n");
  461. #endif DEBUG_TEXT_DRAWING
  462.  
  463.     /* Move pen. */
  464.     SetStdProcs(&stdProcs);
  465.     CallPascal(byteCount, textBuffer, numer, denom, stdProcs.textProc);
  466. }  /* printOneWord */
  467.